package com.yupi.springbootinit.statemachine.processor;

import com.yupi.springbootinit.statemachine.core.StateContext;
import com.yupi.springbootinit.statemachine.core.StateProcessor;
import com.yupi.springbootinit.statemachine.enums.ProductionScheduleStateEnum;
import com.yupi.springbootinit.statemachine.enums.ProductionScheduleEventEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 生产排期状态处理器
 * 处理生产排期状态转换的业务逻辑
 */
@Slf4j
@Component
public class ProductionScheduleStateProcessor implements StateProcessor<ProductionScheduleStateEnum, ProductionScheduleEventEnum> {
    
    @Override
    public boolean beforeTransition(StateContext context) {
        log.info("生产排期状态转换前置处理: 实体[{}] {} -> {}", 
            context.getEntityId(),
            context.getCurrentState().getCode(),
            context.getTargetState().getCode());
        
        ProductionScheduleStateEnum currentState = (ProductionScheduleStateEnum) context.getCurrentState();
        ProductionScheduleStateEnum targetState = (ProductionScheduleStateEnum) context.getTargetState();
        
        switch (currentState) {
            case EDITING:
                return handleEditingToPublished(context);
            case PUBLISHED:
                return handlePublishedToAdjusted(context);
            case ADJUSTED:
                return handleAdjustedToPublished(context);
            default:
                return true;
        }
    }
    
    @Override
    public void afterTransition(StateContext context) {
        log.info("生产排期状态转换后置处理: 实体[{}] 转换完成", context.getEntityId());
        
        ProductionScheduleStateEnum targetState = (ProductionScheduleStateEnum) context.getTargetState();
        
        // 根据目标状态执行相应的后置处理
        switch (targetState) {
            case PUBLISHED:
                handleAfterPublish(context);
                break;
            case ADJUSTED:
                handleAfterAdjust(context);
                break;
        }
        
        // 发送通知
        sendNotification(context);
    }
    
    @Override
    public void onTransitionError(StateContext context, Exception exception) {
        log.error("生产排期状态转换失败: 实体[{}] {} -> {}, 错误: {}", 
            context.getEntityId(),
            context.getCurrentState().getCode(),
            context.getTargetState().getCode(),
            exception.getMessage());
        
        // 记录错误并发送告警
        recordError(context, exception);
    }
    
    @Override
    public String getSupportedStateType() {
        return "PRODUCTION_SCHEDULE";
    }
    
    /**
     * 处理编辑中到已发布的转换
     */
    private boolean handleEditingToPublished(StateContext context) {
        Long scheduleId = context.getEntityId();
        log.debug("检查生产排期[{}]发布条件", scheduleId);
        
        // 检查排期是否完整
        if (!checkScheduleComplete(scheduleId)) {
            log.warn("生产排期[{}]信息不完整，不能发布", scheduleId);
            return false;
        }
        
        // 检查工序时间安排是否合理
        if (!validateProcessTiming(scheduleId)) {
            log.warn("生产排期[{}]工序时间安排不合理", scheduleId);
            return false;
        }
        
        // 检查资源冲突
        if (hasResourceConflict(scheduleId)) {
            log.warn("生产排期[{}]存在资源冲突", scheduleId);
            return false;
        }
        
        return true;
    }
    
    /**
     * 处理已发布到已调整的转换
     */
    private boolean handlePublishedToAdjusted(StateContext context) {
        Long scheduleId = context.getEntityId();
        log.debug("检查生产排期[{}]调整条件", scheduleId);
        
        // 检查是否有正在执行的工序
        if (hasActiveProcesses(scheduleId)) {
            log.warn("生产排期[{}]有正在执行的工序，调整需要特殊处理", scheduleId);
            // 可以允许调整，但需要特殊处理
        }
        
        return true;
    }
    
    /**
     * 处理已调整到已发布的转换（重新发布）
     */
    private boolean handleAdjustedToPublished(StateContext context) {
        Long scheduleId = context.getEntityId();
        log.debug("检查生产排期[{}]重新发布条件", scheduleId);
        
        // 重新验证排期完整性
        return handleEditingToPublished(context);
    }
    
    /**
     * 排期发布后的处理
     */
    private void handleAfterPublish(StateContext context) {
        Long scheduleId = context.getEntityId();
        ProductionScheduleStateEnum currentState = (ProductionScheduleStateEnum) context.getCurrentState();
        
        if (currentState == ProductionScheduleStateEnum.EDITING) {
            // 首次发布
            handleFirstTimePublish(scheduleId);
        } else if (currentState == ProductionScheduleStateEnum.ADJUSTED) {
            // 重新发布
            handleRepublish(scheduleId);
        }
        
        // 更新发布时间和发布人
        updatePublishInfo(scheduleId, context.getOperatorId(), context.getOperatorName());
        
        // 生成工序实例
        generateProcessInstances(scheduleId);
        
        // 通知生产部开始执行
        notifyProductionDepartment(scheduleId);
        
        // 更新订单状态为排期已发布
        updateOrderStatus(scheduleId);
        
        log.info("生产排期[{}]已发布", scheduleId);
    }
    
    /**
     * 排期调整后的处理
     */
    private void handleAfterAdjust(StateContext context) {
        Long scheduleId = context.getEntityId();
        
        // 记录调整历史
        recordAdjustmentHistory(scheduleId, context);
        
        // 暂停相关工序执行
        pauseAffectedProcesses(scheduleId);
        
        // 通知相关部门排期调整
        notifyScheduleAdjustment(scheduleId);
        
        log.info("生产排期[{}]已标记为调整", scheduleId);
    }
    
    /**
     * 首次发布处理
     */
    private void handleFirstTimePublish(Long scheduleId) {
        // 生成排期版本号
        generateScheduleVersion(scheduleId);
        
        // 锁定工艺单版本
        lockProcessSheetVersion(scheduleId);
        
        // 分配资源
        allocateResources(scheduleId);
        
        log.info("生产排期[{}]首次发布完成", scheduleId);
    }
    
    /**
     * 重新发布处理
     */
    private void handleRepublish(Long scheduleId) {
        // 更新版本号
        updateScheduleVersion(scheduleId);
        
        // 比较调整内容
        compareAndRecordChanges(scheduleId);
        
        // 重新分配资源
        reallocateResources(scheduleId);
        
        // 恢复暂停的工序
        resumePausedProcesses(scheduleId);
        
        log.info("生产排期[{}]重新发布完成", scheduleId);
    }
    
    /**
     * 发送通知
     */
    private void sendNotification(StateContext context) {
        ProductionScheduleStateEnum targetState = (ProductionScheduleStateEnum) context.getTargetState();
        Long scheduleId = context.getEntityId();
        
        switch (targetState) {
            case PUBLISHED:
                if (context.getCurrentState() == ProductionScheduleStateEnum.EDITING) {
                    log.info("通知生产部: 生产排期[{}]已发布，可开始执行", scheduleId);
                    log.info("通知项目部: 生产排期[{}]已发布", scheduleId);
                } else {
                    log.info("通知生产部: 生产排期[{}]已重新发布", scheduleId);
                }
                break;
            case ADJUSTED:
                log.info("通知相关部门: 生产排期[{}]已调整", scheduleId);
                break;
        }
    }
    
    // 以下为业务逻辑方法的简化实现
    
    private boolean checkScheduleComplete(Long scheduleId) {
        // 检查排期基本信息是否完整
        // - 关联的订单和工艺单
        // - 所有工序都有预计开始/完成时间
        // - 工序责任车间/设备/资源已分配
        log.debug("检查生产排期[{}]完整性", scheduleId);
        return true; // 简化实现
    }
    
    private boolean validateProcessTiming(Long scheduleId) {
        // 验证工序时间安排的合理性
        // - 工序间的时间依赖关系
        // - 工序持续时间是否合理
        // - 交付日期是否能满足
        log.debug("验证生产排期[{}]工序时间安排", scheduleId);
        return true; // 简化实现
    }
    
    private boolean hasResourceConflict(Long scheduleId) {
        // 检查资源冲突
        // - 设备时间冲突
        // - 人员时间冲突
        // - 车间产能冲突
        log.debug("检查生产排期[{}]资源冲突", scheduleId);
        return false; // 简化实现
    }
    
    private boolean hasActiveProcesses(Long scheduleId) {
        // 检查是否有正在执行的工序
        log.debug("检查生产排期[{}]关联的活跃工序", scheduleId);
        return false; // 简化实现
    }
    
    private void updatePublishInfo(Long scheduleId, Long operatorId, String operatorName) {
        // 更新发布时间和发布人信息
        log.debug("更新生产排期[{}]发布信息，发布人: {}", scheduleId, operatorName);
    }
    
    private void generateProcessInstances(Long scheduleId) {
        // 根据排期生成工序实例
        log.debug("为生产排期[{}]生成工序实例", scheduleId);
    }
    
    private void notifyProductionDepartment(Long scheduleId) {
        // 通知生产部开始执行
        log.debug("通知生产部执行生产排期[{}]", scheduleId);
    }
    
    private void updateOrderStatus(Long scheduleId) {
        // 更新关联订单状态为排期已发布
        log.debug("更新生产排期[{}]关联订单状态", scheduleId);
    }
    
    private void recordAdjustmentHistory(Long scheduleId, StateContext context) {
        // 记录调整历史
        log.debug("记录生产排期[{}]调整历史", scheduleId);
    }
    
    private void pauseAffectedProcesses(Long scheduleId) {
        // 暂停受影响的工序执行
        log.debug("暂停生产排期[{}]受影响的工序", scheduleId);
    }
    
    private void notifyScheduleAdjustment(Long scheduleId) {
        // 通知相关部门排期调整
        log.debug("通知相关部门生产排期[{}]调整", scheduleId);
    }
    
    private void generateScheduleVersion(Long scheduleId) {
        // 生成排期版本号
        log.debug("为生产排期[{}]生成版本号", scheduleId);
    }
    
    private void lockProcessSheetVersion(Long scheduleId) {
        // 锁定工艺单版本
        log.debug("锁定生产排期[{}]关联的工艺单版本", scheduleId);
    }
    
    private void allocateResources(Long scheduleId) {
        // 分配资源
        log.debug("为生产排期[{}]分配资源", scheduleId);
    }
    
    private void updateScheduleVersion(Long scheduleId) {
        // 更新版本号
        log.debug("更新生产排期[{}]版本号", scheduleId);
    }
    
    private void compareAndRecordChanges(Long scheduleId) {
        // 比较并记录变更内容
        log.debug("比较并记录生产排期[{}]变更内容", scheduleId);
    }
    
    private void reallocateResources(Long scheduleId) {
        // 重新分配资源
        log.debug("重新分配生产排期[{}]资源", scheduleId);
    }
    
    private void resumePausedProcesses(Long scheduleId) {
        // 恢复暂停的工序
        log.debug("恢复生产排期[{}]暂停的工序", scheduleId);
    }
    
    private void recordError(StateContext context, Exception exception) {
        // 记录错误信息
        log.error("生产排期[{}]状态转换错误: {}", context.getEntityId(), exception.getMessage());
    }
}